import numpy as np
import data_inputer
from mealpy import FloatVar, GA, Optimizer,IntegerVar
import threading
from map_manager import MapManager
from node_class import Node
import time
import GA_best_road
import math
_Task_Positions:list=None
_Robot_Positions:list=None
_Adjacency_Matrix=None
nodes_data=data_inputer.NODES_DATA
_RES=[]
_PRICES=[]
def sort_two(a:int,b:int):
    if(a>b):
        return (a,b)
    else:
        return (b,a)
def tsp_greedy(travel_list:list[int],start_id,adjacency_matrix:dict):
    '''
    旅行商 贪心算法解
    '''
    t_l=travel_list.copy()
    p=start_id
    res=[]
    price=0
    while(len(t_l)>0):
        min_index=0
        min_id=t_l[min_index]
        min_val=adjacency_matrix[sort_two(p,min_id)][0]
        for i in range(1,len(t_l)):
            val=adjacency_matrix[sort_two(p,t_l[i])][0]
            if(min_val>val):
                min_id=t_l[i]
                min_val=val
                min_index=i
        del t_l[min_index]
        p=min_id
        res.append(min_id)
        if(min_val<float("inf")):
            price+=min_val
        else:
            price+=1000
    return res,price
        
            
def get_adjacency_matrix(task_position,robot_position,nodes_data)->dict:
    '''
    遗传算法计算目标点的邻接矩阵{(id_a,id_b):(score,road:list)}
    '''
    res={}
    start_ps=task_position+robot_position
    for start_id in start_ps:
        for end_id in task_position:
            if(start_id==end_id):
                res[sort_two(start_id,end_id)]=(0,[start_id])
                continue
            is_near,road,score=GA_best_road.GA_Touch(nodes_data,start_id,end_id)
            if(is_near==False):
                res[sort_two(start_id,end_id)]=(float("inf"),None)
                continue
            res[sort_two(start_id,end_id)]=(score,road)  
    return res
def objective_function(solution):
    global _Adjacency_Matrix,_Robot_Positions,_RES,_PRICES
    _RES=[]
    _PRICES=[]
    #travel_lists=get_task_travel_lists(solution)
    travel_lists=split_task(solution)
    for i in range(len(_Robot_Positions)):
       best_list,price= tsp_greedy(travel_lists[i],_Robot_Positions[i],_Adjacency_Matrix)
       #print(best_list)
       _PRICES.append(price)
       _RES.append(best_list)
    for i in range(len(_RES)):
        print(_RES[i],_PRICES[i])
    print()
    return max(_PRICES)*100       

def GA_Core(nodes_data:dict,task_positions:list,robot_positions:list):
    '''
    节点数据，目标点，机器人初始点
    '''
    global _Adjacency_Matrix,_Robot_Positions,_Task_Positions
    _Robot_Positions=robot_positions
    _Task_Positions=task_positions
    # lb=[0]*len(task_positions)*len(robot_positions)+[0]*len(task_positions)
    # ub=[1]*len(task_positions)*len(robot_positions)+list(range(len(task_positions)))
    lb=[0]*len(robot_positions)+[0]*len(task_positions)
    ub=[math.lcm(*range(1,len(task_positions)))]*len(robot_positions)+list(range(len(task_positions)))
    _Adjacency_Matrix=get_adjacency_matrix(task_positions,robot_positions,nodes_data)
    problem = {
        "obj_func": objective_function,
        "bounds": IntegerVar(lb, ub),
        "minmax": "min",
    }
    models = [
        GA.BaseGA(epoch=50, pop_size=50, pc=0.8, pm=0.5),
    ]
    for model in models:
        g_best = model.solve(problem)
        objective_function(g_best.solution)
        model.history.save_global_objectives_chart(filename="goc")
        model.history.save_local_objectives_chart(filename="loc")
        for i in range(len(robot_positions)):
            print(robot_positions[i],_RES[i])

        return 0
    

def shuffle(lis,solution_random):
    result = lis[:]
    for i in range(1, len(lis)):
        j =int(solution_random[i])
        result[i] = result[j]
        result[j] = lis[i]
    return result
def split_task_count(rand_list:list):
    global _Task_Positions,_Robot_Positions
    res=[]
    task_count=len(_Task_Positions)
    for i in range(len(_Robot_Positions)-1):
        n=rand_list[i]%(task_count+1)
        task_count-=n
        res.append(int(n))
    res.append(int(task_count))
    return res
def split_task(solution):
    global _Task_Positions,_Robot_Positions
    rand_list=solution[:len(_Robot_Positions)-1]
    task_random=solution[len(_Robot_Positions)-1:]
    tasks_poor=shuffle(_Task_Positions,task_random)
    split_vals=split_task_count(rand_list)
    res=[]
    #print(split_vals)
    for i in range(len(_Robot_Positions)):
        res.append(tasks_poor[:split_vals[i]])
        tasks_poor=tasks_poor[split_vals[i]:]
    return res   
def get_task_travel_lists(solution)->list[list[int]]:
    global _Robot_Positions,_Task_Positions
    res=[]
    check=[0]*len(_Task_Positions)
    for i in range(len(_Robot_Positions)):
        task_will_do=[]
        for j in range(len(_Task_Positions)):
            if(solution[i*len(_Task_Positions)+j]==1 and check[j]==0):
                task_will_do.append(_Task_Positions[j])
                check[j]=1
        res.append(task_will_do)
    return res
# solution=[1]*len(task_position)*len(robot_position)
# print(get_task_travel_lists(solution))
# print(tsp_greedy(_Task_Positions,2,get_adjacency_matrix(_Task_Positions,[2],nodes_data)))
GA_Core(nodes_data,[25,27,29,40,49,65],[2,5,48])
#GA_Core(nodes_data,[25,27,29],[2,5,3])
print(_Adjacency_Matrix)
  
            
    




# print(math.lcm(*range(1,10)))
# print(split_task([100,37,45]))